package com.yxd.demo.util;

import com.yxd.demo.domain.Rule;
import com.yxd.demo.rule.PriceRule;
import com.yxd.demo.rule.ProductRule;
import com.yxd.demo.rule.SelectRule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.mvel.MVELRule;
import org.jeasy.rules.support.composite.ActivationRuleGroup;
import org.jeasy.rules.support.composite.CompositeRule;
import org.jeasy.rules.support.composite.ConditionalRuleGroup;
import org.jeasy.rules.support.composite.UnitRuleGroup;
import org.mvel2.ParserContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author: yxd
 * @date: 2022/8/1 10:50
 */
@Component
public class RuleUtil {
    @Autowired
    @Qualifier("defaultRuleEngine")
    private RulesEngine rulesEngine;

    @Autowired
    @Qualifier("parserContext")
    private ParserContext parserContext;

    @Autowired
    @Qualifier("priceRule")
    private PriceRule priceRule;

    @Autowired
    @Qualifier("productRule")
    private ProductRule productRule;

    @Autowired
    @Qualifier("selectRule")
    private SelectRule selectRule;

    public void fireRule(List<Rule> ruleList, Facts facts) {
        Rules rules = new Rules();
        Map<Long, Rule> map = ruleList.stream().filter(Objects::nonNull).collect(Collectors.toMap(Rule::getRuleId, p -> p));
        for (Rule rule : ruleList) {
            if (Objects.equals(rule.getIsComposited(), 0) && !Objects.equals(rule.getRuleType(), 1)) {
                rules.register(createRule(rule, parserContext));
            } else if (Objects.equals(rule.getIsComposited(), 1)){
                CompositeRule compositeRule;
                switch (rule.getCompositeRuleType()) {
                    case 1:
                        compositeRule = new UnitRuleGroup();
                        break;
                    case 2:
                        compositeRule = new ActivationRuleGroup();
                        break;
                    case 3:
                        compositeRule = new ConditionalRuleGroup();
                        break;
                    default:
                        throw new IllegalArgumentException("Invalid composite rule type");
                }
                compositeRule.setDescription(rule.getDescription());
                compositeRule.setPriority(rule.getPriority());
                List<Long> ruleIdList = Arrays.stream(rule.getCompositeRuleIds().split(",")).map(Long::valueOf).collect(Collectors.toList());
                for (Long ruleId : ruleIdList) {
                    if (!map.containsKey(ruleId)) {
                        continue;
                    }
                    Rule childRule = map.get(ruleId);
                    compositeRule.addRule(createRule(childRule, parserContext));
                }
                rules.register(compositeRule);
            }
        }
        rulesEngine.fire(rules, facts);
    }

    private MVELRule createRule(Rule rule, ParserContext parserContext) {
        MVELRule mvelRule = new MVELRule(parserContext)
                .name(rule.getName())
                .description(rule.getDescription())
                .priority(rule.getPriority())
                .when(rule.getConditions());
        String[] actions = rule.getAction().split("-");
        for (String action : actions) {
            mvelRule.then(action);
        }
        return mvelRule;
    }

    public void fireRuleWithAnnotation(Facts facts){
        Rules rules = new Rules();
        rules.register(priceRule, productRule, selectRule);
        rulesEngine.fire(rules, facts);
    }
}
